package com.freedom.monitor.myeye.client.report;

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;

import com.freedom.monitor.myeye.client.utils.Logger;
import com.freedom.monitor.myeye.client.utils.PartitionUtils;
import com.freedom.monitor.myeye.commmon.utils.StringUtils;

@SuppressWarnings("rawtypes")
public class ReportMap {
	@SuppressWarnings("unused")
	private static Logger logger = Logger.getLogger(ReportMap.class);

	//
	private static ConcurrentHashMap<String, Object> GLOBAL_REPORT_MAP = null;// map
																				// contains
																				// report
	private static BiFunction GLOBAL_BI_FUNCTION = null;

	static {
		GLOBAL_REPORT_MAP = new ConcurrentHashMap<String, Object>(512);// 512对应着1024个桶
		GLOBAL_BI_FUNCTION = new BiFunction() {
			//
			private HashMap merge(HashMap<String, Statistics> map, Report report) {
				String key = report.getSubKey();
				Statistics statistics = map.get(key);
				if (null == statistics) {// 第1次出现
					map.put(key, new Statistics(report));
				} else {// 之前有了，就合并
					statistics.addReport(report);
				}
				return map;
			}

			//
			@SuppressWarnings("unchecked")
			@Override
			public Object apply(Object oldObject, Object newObject) {
				// 1)先构造好map
				HashMap<String, Statistics> map = null;
				if (oldObject instanceof Report) {
					map = new HashMap<String, Statistics>();
					map.put(((Report) oldObject).getSubKey(), new Statistics(((Report) oldObject)));
				} else {
					map = (HashMap) oldObject;
				}
				// 2)返回map,回置于ConcurrentHashMap容器内
				return merge(map, (Report) newObject);
			}
		};
	}

	// 接下来，可以自由定义ReportMap的类内容,会有很多线程同时调用这个方法
	@SuppressWarnings("unchecked")
	public static void handle(Report report) {
		// logger.debug("handle report ---" + report);
		// 如果不使用当前时间的话，同一个key会始终等待同一个锁，性能急剧降低,以空间换时间
		String key = StringUtils.unionByMagicKey(//
				report.getProduct(),
				StringUtils.unionByMagicKey(//
						report.getService(), //
						"" + (
						//
						( //
						Math.abs(report.getSubKey().hashCode()) + System.nanoTime()// 使用纳秒，保证即使是同一个key,也尽可能的分散
						) //
								% PartitionUtils.getPartition())// 字符串结束
				)//
		);
		GLOBAL_REPORT_MAP.merge(key, report, GLOBAL_BI_FUNCTION);
		// logger.debug("" + obj);
	}

	public static Object getAndRemove(String key) {
		return GLOBAL_REPORT_MAP.remove(key);
	}
}